<?php
/**
 * 商品预定价计算
 */

namespace app\common\service\product;

use app\common\model\Channel;
use app\common\model\ExpressCountry;
use GuzzleHttp\Client;
use app\common\library\Tools;
use app\common\service\BaseService;
use Env;
use Exception;
use think\Db;
use think\exception\DbException;
use think\facade\Log;

class CalculatePrePriceService extends BaseService
{
    private $client;
    private $accessKey;
    private $secretKey;
    private $associateTag; //关联标签
    private $region; //区域（站点）
    private $profitMargin; // 利润率
    private $shippingCost; // 运费
    private $taxRate; // 税率

    //todo 整理最后的预售价逻辑，并开发对应程序
    //【成本=拿货价+运费+成交费（亚马逊佣金）+ 预设退款（订单总价%）+ 税费（国家税费） + 预设广告费（）+ 其他费用（什么打包费，包装法，注册公司费用等等，初始值1000（取1%） 相当于，每个取10块）】
    
    public function __construct($accessKey, $secretKey, $associateTag, $region = 'us', $profitMargin = 0.2, $shippingCost = 5.0, $taxRate = 0.1)
    {
        $this->client = new Client(['base_uri' => 'https://webservices.amazon.com']);
        $this->accessKey = $accessKey;
        $this->secretKey = $secretKey;
        $this->associateTag = $associateTag;
        $this->region = $region;
        $this->profitMargin = $profitMargin;
        $this->shippingCost = $shippingCost;
        $this->taxRate = $taxRate;
    }

    public function getAttr($attrName)
    {
        return $this->$attrName;
    }
    public function setAttr($attrName,$value)
    {
        $this->$attrName = $value;
    }

    /**
     * 计算产品预售价
     * DateTime : 2024/5/21 20:47
     * @Author : kinghuang
     * @param $asin
     * @return array|null
     */
    public function getProductEstimate($asin)
    {
        $response = $this->fetchProductDetails($asin);
        if (!$response) {
            return null;
        }

        $price = $this->extractPrice($response);
        if ($price === null) {
            return null;
        }

        $estimatedPrice = $this->calculateEstimatedPrice($price);

        return [
            'asin' => $asin,
            'cost_price' => $price,
            'estimated_price' => $estimatedPrice
        ];
    }

    /**
     * 获取产品详情
     * DateTime : 2024/5/21 20:48
     * @Author : kinghuang
     * @param $asin
     * @return \SimpleXMLElement|null
     */
    private function fetchProductDetails($asin)
    {
        $params = [
            'Service' => 'AWSECommerceService',
            'Operation' => 'ItemLookup',
            'ItemId' => $asin,
            'IdType' => 'ASIN',
            'ResponseGroup' => 'Offers,ItemAttributes',
            'AWSAccessKeyId' => $this->accessKey,
            'AssociateTag' => $this->associateTag,
            'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
        ];

        $params['Signature'] = $this->generateSignature($params);

        try {
            $response = $this->client->request('GET', '/onca/xml', [
                'query' => $params
            ]);

            return simplexml_load_string($response->getBody()->getContents());
        } catch (\Exception $e) {
            echo 'Error: ' . $e->getMessage();
            return null;
        }
    }

    /**
     * 亚马逊签名
     * DateTime : 2024/5/21 20:45
     * @Author : kinghuang
     * @param $params
     * @return string
     */
    private function generateSignature($params)
    {
        ksort($params);
        $queryString = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
        $stringToSign = "GET\nwebservices.amazon.com\n/onca/xml\n" . $queryString;
        $signature = base64_encode(hash_hmac('sha256', $stringToSign, $this->secretKey, true));

        return $signature;
    }

    private function extractPrice($response)
    {
        if (isset($response->Items->Item->OfferSummary->LowestNewPrice->Amount)) {
            return (float)$response->Items->Item->OfferSummary->LowestNewPrice->Amount / 100;
        }
        return null;
    }

    private function calculateEstimatedPrice($costPrice)
    {
        // 计算税费
        $tax = $costPrice * $this->taxRate;

        // 计算利润
        $profit = $costPrice * $this->profitMargin;

        // 计算最终预定价
        $estimatedPrice = $costPrice + $tax + $this->shippingCost + $profit;

        return round($estimatedPrice, 2); // 保留两位小数
    }

    /**
     * 根据重量算运费
     * @param $expressCountryID
     * @param $weight
     * @return float
     */
    public static function calculateShippingCost($expressCountryID, $weight)
    {
        #1.根据国家物流ID获取物流信息
        $expressCountry = ExpressCountry::with('quotation')->get($expressCountryID)->toArray();
        #2.对每个物流，执行计算，得出运费和时间
        #根据重量匹配合适的区间报价单，如果没有匹配的，默认取最后一条报价单（最后一条是最重的一条报价单）
        $qCount = count($expressCountry['quotation']); //报价单总数
        $qArr = $expressCountry['quotation'];
        $q = []; //匹配重量的报价单
        foreach ($qArr as $qk=>$qv ){
            if(($qv['start_weight'] < $weight && $weight <= $qv['end_weight']) || ($qk == $qCount - 1) ){
                $q = $qv;
                break;
            }
        }

        //没有报价单，直接返回0
        if(empty($q)) return 0;

        $expressFreight = 0; //运费结果
        $isOverweight = ($weight - $q['end_weight']) > 0 ? true : false; //是否超重（上下浮动50g）
        if($isOverweight){
            ##超重算法（重量单位转Kg）【重量*运费 + 挂号费 + 向上取整（重量 - 结束重量 - 0.05kg[边界允许值]）*超重运费】
            $expressFreight = ($weight/1000)*$q['price'] + $q['register_price'] + $q['continue_weight_price']*ceil(($weight - $q['end_weight'] - 50)/1000);
        }
        else{
            ##标准算法（重量单位转Kg）【重量*运费+挂号费
            $expressFreight = ($weight/1000)*$q['price'] + $q['register_price'];
        }
        
        return round($expressFreight, 2); // 保留两位小数
        
    }

    /**
     * 根据重量算运费(列表)
     * @param $countryCode
     * @param $weight
     * @return float
     */
    public static function getShippingCostList($countryCode, $weight)
    {
        #1.根据国家获取可行的物流列表
        $expressCountry = ExpressCountry::with('quotation')->all(['country_code' => $countryCode])->each(function ($v,$k) use($weight)
        {
            #2.对每个物流，执行计算，得出运费和时间
            //整合f返回数据所需字段【物流编号、渠道、承诺天数、平均时效/天、妥投率、最大重量、是否超重、运费】
            $v['channel'] = Channel::getNameById($v['channel_id']); //渠道
            $v['end_weight'] = '未知'; //最大重量
            $v['is_overweight'] = '未知'; //是否超重
            $v['express_freight'] = 0; //运费

            #根据重量匹配合适的区间报价单，如果没有匹配的，默认取最后一条报价单（最后一条是最重的一条报价单）
            $qCount = $v->quotation->count(); //报价单总数
            $qArr = $v->quotation->toArray();
            $q = []; //匹配重量的报价单
            foreach ($qArr as $qk=>$qv ){
                if(($qv['start_weight'] < $weight && $weight <= $qv['end_weight']) || ($qk == $qCount - 1) ){
                    $q = $qv;
                    break;
                }
            }

            //没有报价单，直接跳过
            if(empty($q)) return $v;

            $isOverweight = ($weight - $q['end_weight']) > 0 ? true : false; //是否超重（上下浮动50g）
            $expressFreight = 0; //运费结果
            if($isOverweight){
                ##超重算法（重量单位转Kg）【重量*运费 + 挂号费 + 向上取整（重量 - 结束重量 - 0.05kg[边界允许值]）*超重运费】
                $expressFreight = ($weight/1000)*$q['price'] + $q['register_price'] + $q['continue_weight_price']*ceil(($weight - $q['end_weight'] - 50)/1000);

                //echo "超重算法".PHP_EOL;
                //echo $expressFreight;
            }
            else{
                ##标准算法（重量单位转Kg）【重量*运费+挂号费
                $expressFreight = ($weight/1000)*$q['price'] + $q['register_price'];

                //echo "标准算法".PHP_EOL;
                //echo $expressFreight;
            }

            $v['end_weight'] = $q['end_weight'];
            $v['is_overweight'] = $isOverweight ? '是' : "否";
            $v['express_freight'] = $expressFreight;
            return $v;

        })->toArray();

        //排序【按运费的从低到高排序，用<,反之用>】
        usort($expressCountry, function($a, $b) {
            if ($a['express_freight'] == $b['express_freight']) {
                return 0;
            }
            return ($a['express_freight'] < $b['express_freight']) ? -1 : 1;
        });

        return $expressCountry;

    }
    
}

/*// 使用示例
$accessKey = 'your_aws_access_key';
$secretKey = 'your_aws_secret_key';
$associateTag = 'your_associate_tag';
$asin = 'B01K1C94E4';

$estimator = new AmazonProductEstimator($accessKey, $secretKey, $associateTag);
$productEstimate = $estimator->getProductEstimate($asin);

if ($productEstimate) {
    echo 'ASIN: ' . $productEstimate['asin'] . PHP_EOL;
    echo 'Cost Price: $' . $productEstimate['cost_price'] . PHP_EOL;
    echo 'Estimated Price: $' . $productEstimate['estimated_price'] . PHP_EOL;
} else {
    echo 'Failed to fetch product estimate.' . PHP_EOL;
}*/
